/**
 * 
 */
package org.apache.struts2.gtgrid;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import net.sf.json.JSONArray;
import net.sf.json.JSONObject;

import org.apache.struts2.StrutsStatics;
import org.apache.struts2.gtgrid.model.GtColumnInfo;
import org.apache.struts2.gtgrid.model.GtFilterInfo;
import org.apache.struts2.gtgrid.model.GtGridInfo;
import org.apache.struts2.gtgrid.model.GtPageInfo;
import org.apache.struts2.gtgrid.model.GtSortInfo;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import com.opensymphony.xwork2.util.logging.Logger;
import com.opensymphony.xwork2.util.logging.LoggerFactory;

/**
 * 拦截gt-grid传过来的_gt_json字符串，将该字符串解释成各种对象，并inject到action中
 * 
 * <pre>
 * gt-grid's objects include:
 * {@link org.apache.struts2.gtgrid.model.GtGridInfo},
 * {@link org.apache.struts2.gt_grid.model.IGtPageInof},
 * {@link org.apache.struts2.gtgrid.model.GtColumnInfo},
 * {@link org.apache.struts2.gtgrid.model.GtSortInfo},
 * {@link org.apache.struts2.gtgrid.model.GtFilterInfo}
 * 
 * </pre>
 * 
 * @author Stevie
 * @since 2009-12-3
 * @version 1.0
 * 
 */
public class GtGridInterceptor extends AbstractInterceptor {
	private static final long serialVersionUID = 7687752742000689155L;
	private static final Logger LOG = LoggerFactory
			.getLogger(GtGridInterceptor.class);

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.opensymphony.xwork2.interceptor.AbstractInterceptor#intercept(com
	 * .opensymphony.xwork2.ActionInvocation)
	 */
	@SuppressWarnings("unchecked")
	@Override
	public String intercept(ActionInvocation invocation) throws Exception {
		if (LOG.isDebugEnabled())
			LOG.debug("start interception");

		ActionContext actionContext = invocation.getInvocationContext();
		HttpServletRequest request = (HttpServletRequest) actionContext
				.get(StrutsStatics.HTTP_REQUEST);

		String gtJsonIn = request.getParameter(GtGridKeywords.GT_JSON_NAME.getKeyword());
		if (null != gtJsonIn) {
			JSONObject jsonObject = JSONObject.fromObject(gtJsonIn);
			String action = jsonObject.getString(GtGridKeywords.GT_ACTION_NAME.getKeyword());
//			String recordType = jsonObject.has("remotePaging") ? jsonObject
//					.getString("recordType") : null;
//			boolean remotePaging = jsonObject.has("remotePaging") ? jsonObject
//					.getBoolean("remotePaging") : false;

//			final ValueStack stack = ActionContext.getContext().getValueStack();
			GtGridAware actionIn = null;
			if (invocation.getAction() instanceof GtGridAware) {
				actionIn = (GtGridAware) invocation.getAction();
			}
			if (LOG.isDebugEnabled())
				LOG.debug("GtGridAware: "+ actionIn);
			
			GtGridInfo gridInfo = getGridInfo(jsonObject);
//			stack.setValue("gridInfo", gridInfo);
			if (null != actionIn) {
				actionIn.setGridInfo(gridInfo);
				actionIn.setParameterMap(request.getParameterMap());
			}
			if (LOG.isDebugEnabled())
				LOG.debug("action: "+ action);
			if (GtGridKeywords.GT_LOAD_NAME.getKeyword().equalsIgnoreCase(action)) { //load data
				GtPageInfo pageInfo = getPageInfo(jsonObject);
				List<GtSortInfo> sortInfos = getSortInfos(jsonObject);
				List<GtFilterInfo> filterInfos = getFilterInfos(jsonObject);

//				stack.setValue("pageInfo", pageInfo);
//				stack.setValue("sortInfo", sortInfos);
//				stack.setValue("filterInfo", filterInfos);

				if (null != actionIn) {
					actionIn.setPageInfo(pageInfo);
					actionIn.setSortInfos(sortInfos);
					actionIn.setFilterInfos(filterInfos);
				}
			} else if (GtGridKeywords.GT_SAVE_NAME.getKeyword().equalsIgnoreCase(action)) { //save data
				JSONArray insertedRecords = getInsertedRecords(jsonObject);
				JSONArray updatedRecords = getUpdatedRecords(jsonObject);
				JSONArray deletedRecords = getDeletedRecords(jsonObject);
//				stack.setValue("insertedRecords", insertedRecords);
//				stack.setValue("updatedRecords", updatedRecords);
//				stack.setValue("deletedRecords", deletedRecords);
				
				if (null != actionIn) {
					actionIn.setInsertedRecords(insertedRecords);
					actionIn.setUpdatedRecords(updatedRecords);
					actionIn.setDeletedRecords(deletedRecords);
				}
			} else if (GtGridKeywords.GT_EXPORT_NAME.getKeyword().equalsIgnoreCase(action)) { //export excel
				List<GtColumnInfo> columnInfos = getColumnInfos(jsonObject);
//				stack.setValue("columnInfo", columnInfos);

				if (null != actionIn)
					actionIn.setColumnInfos(columnInfos);
			}
		}
		return invocation.invoke();
	}

	/**
	 * parse _gt_json, then generate GtGridInfo oject
	 * 
	 * @param jsonObject
	 * @return
	 */
	private GtGridInfo getGridInfo(JSONObject jsonObject) {
		JSONObject modelJS = jsonObject.getJSONObject(GtGridKeywords.GT_GRIDINFO_NAME.getKeyword());
		if (modelJS != null) {
			return (GtGridInfo) JSONObject.toBean(modelJS, GtGridInfo.class);
		}
		return null;
	}

	/**
	 * PageInfo
	 * 
	 * @param jsonObject
	 * @return
	 */
	private GtPageInfo getPageInfo(JSONObject jsonObject) {
		JSONObject modelJS = jsonObject.getJSONObject(GtGridKeywords.GT_PAGEINFO_NAME.getKeyword());
		if (modelJS != null) {
			return (GtPageInfo) JSONObject.toBean(modelJS, GtPageInfo.class);
		}
		return null;
	}

	/**
	 * List of SortInfo
	 * 
	 * @param jsonObject
	 * @return
	 */
	private List<GtSortInfo> getSortInfos(JSONObject jsonObject) {
		JSONArray modelJS = jsonObject.getJSONArray(GtGridKeywords.GT_SORTINFO_NAME.getKeyword());
		if (modelJS != null) {
			List<GtSortInfo> sortInfos = new ArrayList<GtSortInfo>(2);
			for (int i = 0; i < modelJS.size(); i++) {
				JSONObject si = modelJS.getJSONObject(i);
				sortInfos.add((GtSortInfo) JSONObject.toBean(si,
						GtSortInfo.class));
			}
			return sortInfos;
		}
		return Collections.emptyList();
	}

	/**
	 * list of filter info
	 * 
	 * @param jsonObject
	 * @return
	 */
	private List<GtFilterInfo> getFilterInfos(JSONObject jsonObject) {
		JSONArray modelJS = jsonObject.getJSONArray(GtGridKeywords.GT_FILTER_NAME.getKeyword());
		if (modelJS != null) {
			List<GtFilterInfo> filterInfos = new ArrayList<GtFilterInfo>(2);
			for (int i = 0; i < modelJS.size(); i++) {
				JSONObject si = modelJS.getJSONObject(i);
				filterInfos.add((GtFilterInfo) JSONObject.toBean(si,
						GtFilterInfo.class));
			}
			return filterInfos;
		}
		return Collections.emptyList();
	}

	/**
	 * list of column info
	 * 
	 * @param jsonObject
	 * @return
	 */
	private List<GtColumnInfo> getColumnInfos(JSONObject jsonObject) {
		JSONArray modelJS = jsonObject.getJSONArray(GtGridKeywords.GT_COLUMN_NAME.getKeyword());
		if (modelJS != null) {
			List<GtColumnInfo> columnInfos = new ArrayList<GtColumnInfo>(2);
			for (int i = 0; i < modelJS.size(); i++) {
				JSONObject si = modelJS.getJSONObject(i);
				columnInfos.add((GtColumnInfo) JSONObject.toBean(si,
						GtColumnInfo.class));
			}
			return columnInfos;
		}
		return Collections.emptyList();
	}

	private JSONArray getUpdatedRecords(JSONObject jsonObject) {
		return getRecordsList(GtGridKeywords.GT_UPDATE_NAME.getKeyword(), jsonObject);
	}

	private JSONArray getInsertedRecords(JSONObject jsonObject) {
		return getRecordsList(GtGridKeywords.GT_INSERT_NAME.getKeyword(), jsonObject);
	}

	private JSONArray getDeletedRecords(JSONObject jsonObject) {
		return getRecordsList(GtGridKeywords.GT_DELETE_NAME.getKeyword(), jsonObject);
	}

	/**
	 * return JSONArray
	 */
	private JSONArray getRecordsList(String rname, JSONObject jsonObject) {
		return jsonObject.getJSONArray(rname);
	}
}
